package com.idealighter.game.games.errentexaspoker;

import com.google.common.collect.Lists;

import com.idealighter.game.core.common.Game;
import com.idealighter.game.dictionary.dic.TexapokerRobotRulesDic;
import com.idealighter.game.dictionary.domain.ErrentexaporkerRoomDomain;
import com.idealighter.game.dictionary.domain.RobotConfigDomain;
import com.idealighter.game.dictionary.domain.TexapokerRobotRulesDomain;
import com.idealighter.game.gamehall.dto.MemInfo;
import com.idealighter.game.gamehall.dto.SeatInfo;
import com.idealighter.game.games.errentexaspoker.message.ReqBetDecisionMsg;
import com.idealighter.game.games.errentexaspoker.message.ReqEnterGameHallMsg;
import com.idealighter.game.games.errentexaspoker.message.ReqEnterRoomMsg;
import com.idealighter.game.games.errentexaspoker.message.ReqEnterTableMsg;
import com.idealighter.game.robot.common.cards.Card;
import com.idealighter.game.robot.common.cards.Cards;
import com.idealighter.game.robot.common.cards.DeckPowerCompare;
import com.idealighter.game.robot.context.ApplicationContext;
import com.idealighter.game.robot.core.Player;
import com.idealighter.utils.code.RandCodeUtil;

import java.util.List;
import java.util.stream.Collectors;

import org.slf4j.LoggerFactory;

/**
 * 二人德州机器人 .
 * 
 * @author zsc .
 * @date 2016年3月24日 上午11:12:15
 *
 */
public class ErrenTexaspokerPlayer extends Player {
  // 上一轮下注的筹码数
  public long curBet = 0;
  // 每次的下注筹码数
  public List<Long> betRecord = Lists.newArrayList();
  // 下注类型
  public int betType = 0;// 0:跟注，1：弃牌，2：加注，3：梭哈, 4:让牌
  public TexapokerRobotRulesDomain domain = new TexapokerRobotRulesDomain();
  // 手上的牌(包括手牌和公共牌，当没有公共牌的时候就只代表手牌)
  public List<Integer> cardList = Lists.newArrayList();
  public List<Integer> handCard = Lists.newArrayList(); // 手牌
  private TexapokerRobotRulesDic texapokerRobotDic =
      ApplicationContext.getBean(TexapokerRobotRulesDic.class);
  private DeckPowerCompare deckPowerCompare = ApplicationContext.getBean(DeckPowerCompare.class);
  private Cards deckCards = ApplicationContext.getBean(Cards.class);
  public ErrentexaporkerRoomDomain roomDomain;

  /**
   * 构造函数.
   * 
   * @param playerId .
   * @param userName .
   * @param roomId .
   * @param initGold .
   * @param totalGameNum .
   * @param tableGameNum .
   */
  public ErrenTexaspokerPlayer(long playerId, String userName, int roomId, int initGold,
      int totalGameNum, int tableGameNum, RobotConfigDomain configDomain,
      ErrentexaporkerRoomDomain roomDomain) {
    super(playerId, userName, roomId, initGold, totalGameNum, tableGameNum, configDomain);
    this.roomDomain = roomDomain;
  }

  /**
   * .
   * 
   * @param maxBet .
   * @param raiseBet .
   */
  public void betDesision(long maxBet, long raiseBet) {

    // handPowerRanker.isHave(domain);
    // betType = RandCodeUtil.random(0, 3);

    final MemInfo memInfo = member(playerId);

    List<Card> cards = Lists.newArrayList();
    List<Card> handCards = Lists.newArrayList();
    cards.addAll(
        cardList.stream().map(card -> deckCards.card(Card.cardSuit(card), Card.cardNumber(card)))
            .collect(Collectors.toList()));
    handCards.addAll(
        handCard.stream().map(card -> deckCards.card(Card.cardSuit(card), Card.cardNumber(card)))
            .collect(Collectors.toList()));
    domain.setCardsNum(getSate());
    deckPowerCompare.isHave(cards, handCards, domain);
    checkShowHandMust(maxBet, raiseBet);
    betType = loadRobotRules();
    // domain.clear();
    long betNum = betNum(maxBet, raiseBet);
    if (betNum > memInfo.getChips()) { // 配置表数据不全后导致采用默认操作导致下注筹码不正确，采取特殊处理
      // if (betType == 0) {//在没有配置数据，默认跟注，筹码不正确，弃牌
      // betType = 1;
      // betNum = 0;
      // }
      // if (betType == 2) {//raise
      // ->能够加注的表示已经读取到配置表中的数据,但是筹码不够，改为跟注(因为没有采用默认操作跟注)
      // betType = 0;
      // betNum = betNum(maxBet, raiseBet);
      // }
      // if (betNum > memInfo.getChips()) {
      // System.err.println("筹码不够");
      // System.err.println("下注失败" + "类型：" + betType + "需要筹码数:" + betNum +
      // "机器人:" + playerInfo.getName() + "机器人携带总筹码数量:" +
      // memInfo.getChips());
      // return;
      // }
      betType = 1; // 筹码不对，直接弃牌处理
      betNum = betNum(maxBet, raiseBet);
      System.err.println("异常弃牌");
    }
    if (betType == 2 && betNum == 0) {
      betNum = memInfo.getChips() < roomDomain.getMinOne() ? 0 : roomDomain.getMinOne();
    }
    if (betType == 1 && maxBet == curBet) {
      betType = 4;
      betNum = 0;
    }
    ReqBetDecisionMsg msg = new ReqBetDecisionMsg();
    msg.setType(betType);
    msg.setBet(betNum);
    // curBet += (int) betNum;
    // bet += betNum;
    betRecord.add(betNum);
    sendMsg(msg);
  }

  private int getSate() {
    int state = 1;
    switch (cardList.size()) {
      case 2:
        state = 1;
        break;
      case 5:
        state = 2;
        break;
      case 6:
        state = 3;
        break;
      case 7:
        state = 4;
        break;
      default:
        break;
    }
    return state;
  }

  private void cardToString() {
    String handcardmsg = "";
    String commoncardmsg = "";
    List<Card> cards = Lists.newArrayList();
    List<Card> handCards = Lists.newArrayList();
    cards.addAll(
        cardList.stream().map(card -> deckCards.card(Card.cardSuit(card), Card.cardNumber(card)))
            .collect(Collectors.toList()));
    handCards.addAll(
        handCard.stream().map(card -> deckCards.card(Card.cardSuit(card), Card.cardNumber(card)))
            .collect(Collectors.toList()));

    List<Card> commonCards = Lists.newArrayList();
    commonCards.addAll(
        cards.stream().filter(card -> !handCards.contains(card)).collect(Collectors.toList()));
    /**
     * 手牌
     */
    for (Card cardString : handCards) {
      handcardmsg += cardString.toString();
    }

    /**
     * 公牌
     */
    for (Card common : commonCards) {
      commoncardmsg += common.toString();
    }

    String msg = "手牌:" + handcardmsg + "公牌:" + commoncardmsg;
    LoggerFactory.getLogger("TexaPokerRuleLog").info(msg);

  }

  /**
   * 跟注后是否还有筹码 .
   */
  private void checkShowHandMust(long maxBet, long raiseBet) {
    MemInfo memInfo = member(playerId);
    if (maxBet - curBet <= memInfo.getChips()) {
      domain.setShowhandMust(1);
    } else {
      domain.setShowhandMust(0);
    }
  }

  private long betNum(long maxBet, long raiseBet) {
    MemInfo memInfo = member(playerId);
    /*
     * long preBet = 0; for (Long record : betRecord) { preBet += record; }
     */
    if (betType == 0) { // call
      return maxBet - curBet;
    } else if (betType == 1) { // fold
      return 0;
    } else if (betType == 2) { // raise
      long bet = maxBet + raiseBet - curBet;
      return bet;
    } else if (betType == 3) { // all in
      return memInfo.getChips();
    } else { // check
      // if (maxBet == 0 && raiseBet == 0) {
      // betType = 1;
      // return 0;
      // }
      return 0;
    }
  }

  private int loadRobotRules() {
    if (!texapokerRobotDic.list().contains(domain)) {
      // System.err.println(domain.toString());
      domain.toString();
      cardToString();
      domain.setTimeMin(texapokerRobotDic.list().get(0).getTimeMin()); // TODO
      // 在没有查询到记录的时候采用默认值(配置表完善后删除)
      domain.setTimeMax(texapokerRobotDic.list().get(0).getTimeMax());
      return randHand(texapokerRobotDic.list().get(0));
    } else {
      for (TexapokerRobotRulesDomain domains : texapokerRobotDic.list()) {
        if (domains.equals(domain)) {
          // System.err.println("Have this Record");
          domain.setTimeMin(domains.getTimeMin());
          domain.setTimeMax(domains.getTimeMax());
          return randHand(domains);
        }
      }
    }
    return 0;
  }

  /**
   * 根据概率随机一种操作.
   *
   * @param domain .
   * @return .
   */
  private int randHand(TexapokerRobotRulesDomain domain) {
    int rand = RandCodeUtil.random(10000);
    if (rand <= domain.getFollow()) {
      return 0; // call
    }
    if (rand <= domain.getFollow() + domain.getFilling()) {
      return 2;
    }
    if (rand <= domain.getFollow() + domain.getFilling() + domain.getShowhand()) {
      return 3;
    }
    if (rand <= domain.getFollow() + domain.getFilling() + domain.getShowhand()
        + domain.getGiveUp()) {
      return 1;
    }
    return 1;
  }

  /**
   * .
   */
  public void resetData() {
    domain = new TexapokerRobotRulesDomain();
    cardList.clear();
    handCard.clear();
    betRecord.clear();
    curBet = 0;
  }

  @Override
  public boolean goldCheck() {

    long gold = playerInfo.getGold();
    if (gold < roomDomain.getLower()) {
      LOG.info("[二人德州扑克]机器人[{}][{}]金币小于房间下限退出游戏", userName, playerId);
      delayLogout();
      return false;
    }

    if (gold > roomDomain.getUpper()) {
      LOG.info("[二人德州扑克]机器人[{}][{}]金币高于房间下限退出游戏", userName, playerId);
      delayLogout();
      return false;
    }

    if (gold < roomDomain.getAfee()) {
      LOG.info("[二人德州扑克]机器人[{}][{}]金币小于台费退出游戏", userName, playerId);
      delayLogout();
      return false;
    }
    return true;
  }

  @Override
  public void enterGameHall() {
    sendMsg(new ReqEnterGameHallMsg());
  }

  @Override
  public void enterRoom() {
    if (rooms.contains(roomId)) {
      if (!goldCheck()) {
        return;
      }
      ReqEnterRoomMsg msg = new ReqEnterRoomMsg();
      msg.setRoomId(roomId);
      sendMsg(msg);
    }
  }

  @Override
  public void enterTable() {
    if (!goldCheck()) {
      return;
    }
    SeatInfo emptySeat = findNoGamingEmptySeat();
    if (emptySeat != null) {
      ReqEnterTableMsg msg = new ReqEnterTableMsg();
      msg.setTableId((int) emptySeat.getTableId());
      msg.setOrder((byte) emptySeat.getOrder());
      msg.setPassword("");
      sendMsg(msg);
    }
  }

  @Override
  public Game game() {
    return Game.ERREN_TEXAPOKER;
  }

  public List<Integer> getCardList() {
    return cardList;
  }

  public void setCardList(List<Integer> cardList) {
    this.cardList = cardList;
  }

  public List<Integer> getHandCard() {
    return handCard;
  }

  public void setHandCard(List<Integer> handCard) {
    this.handCard = handCard;
  }

  @Override
  public boolean enterPwdTableAble() {
    return false;
  }

}
